#include <klib.h>
#include <klib-macros.h>
#include <stdint.h>

#if !defined(__ISA_NATIVE__) || defined(__NATIVE_USE_KLIB__)

size_t strlen(const char *s) {
  assert(s);
  int count = 0;
  while (*s != '\0')
  {
    count++;
    s++;
  }
  return count;
}

char *strcpy(char *dst, const char *src) {
  assert(dst&&src);
  char *ret = dst;
  while ((*dst++ = *src++))
  {
    ;
  }
  return ret;
}

char *strncpy(char *dst, const char *src, size_t n) {
  assert(dst&&src);
  size_t i;
  for (i = 0; i < n && src[i] != '\0'; i++)
    dst[i] = src[i];
  for ( ; i < n; i++)
    dst[i] = '\0';
  return dst;
}

char *strcat(char *dst, const char *src) {
  assert(dst&&src);
  char* ret = dst;
  while (*dst)
  {
    dst++;
  }
  while ((*dst++ = *src++))
  {
    ;
  }
  return ret;
}

int strcmp(const char *s1, const char *s2) {
  assert(s1&&s2);
  while (*s1 == *s2)
  {
    if (*s1 == '\0')
      return 0;
    s1++;
    s2++;
  }
  if (*s1 > *s2)
    return 1;
  else
    return -1;
}

int strncmp(const char *s1, const char *s2, size_t n) {
  assert(s1&&s2);
  while ((*s1 == *s2)&&n)
  {
    s1++;
    s2++;
    n--;
  }
  return (int)(*s1 - *s2);
}

void *memset(void *s, int c, size_t n) {
  assert(s);
  uint8_t *p = (uint8_t*)s;
  while(n--)
  {
    *p++ = c;
  }
  return s;
}

void *memmove(void *dst, const void *src, size_t n) {
  assert(dst&&src);
  void * ret = dst;

  if (dst <= src || dst >= (src + n)) 
  {
    while (n--)
      *(uint8_t*)dst++ = *(uint8_t*)src++;
  }
  else 
  {
    dst += n - 1;
    src += n - 1;
    while (n--)
      *(uint8_t*)dst-- = *(uint8_t*)src--;
  }
  return ret;
}

void *memcpy(void *out, const void *in, size_t n) {
  assert(out && in);
  void *tmp = out;

  while (n--)
  {
    *(uint8_t*)out = *(uint8_t*)in;
    out += sizeof(uint8_t);
    in += sizeof(uint8_t);
  }
  
  return tmp;
}

int memcmp(const void *s1, const void *s2, size_t n) {
  const unsigned char *su1, *su2;
  int res = 0;
  for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, n--)
    if ((res = *su1 - *su2) != 0)
      break;
  return res;
}

#endif
